home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 5 / Apprentice-Release5.iso / Source Code / C / Applications / Fixation 1.3 / game.cpp < prev    next >
Text File  |  1996-04-11  |  42KB  |  1,720 lines

  1. // game.c
  2.  
  3. #include <stdio.h>
  4. #include <stdlib.h>
  5. #include <string.h>
  6.  
  7. #include "mytypes.h"
  8. #include "error.h"
  9.  
  10. #include "globals.h"
  11. #include "menus.h"
  12. #include "window.h"
  13. #include "main.h"
  14. #include "util.h"
  15. #include "preffile.h"
  16. #include "connexions.h"
  17. #include "fastmap.h"
  18. #include "graphics.h"
  19. #include "game.h"
  20. #include "incoming.h"
  21.  
  22. #include "outgoing.h"
  23.  
  24. #define optionkey 0x3A
  25.  
  26. unsigned char km[16];
  27. Game *gGames = nil;
  28.  
  29.  
  30. enum {
  31.     kNoMove = 0,
  32.     kMove,
  33.     kBugMove,
  34.     kSetupMove
  35. };
  36.  
  37. Game *gDragGame = nil;
  38. short gClickType = kNoMove, gOldPiece;
  39. Point gOrigPoint, gDestPoint;
  40.  
  41. static Rect dirty = {0,0,0,0};
  42. static short offx, offy;
  43.  
  44.  
  45. Board initialPosition = {        // this is actually wrong, but it never really gets used . . .
  46.     { WhiteRook, WhiteKnight, WhiteBishop, WhiteQueen,
  47.     WhiteKing, WhiteBishop, WhiteKnight, WhiteRook },
  48.     { WhitePawn, WhitePawn, WhitePawn, WhitePawn,
  49.     WhitePawn, WhitePawn, WhitePawn, WhitePawn },
  50.     { empty, empty, empty, empty,
  51.     empty, empty, empty, empty },
  52.     { empty, empty, empty, empty,
  53.     empty, empty, empty, empty },
  54.     { empty, empty, empty, empty,
  55.     empty, empty, empty, empty },
  56.     { empty, empty, empty, empty,
  57.     empty, empty, empty, empty },
  58.     { BlackPawn, BlackPawn, BlackPawn, BlackPawn,
  59.     BlackPawn, BlackPawn, BlackPawn, BlackPawn },
  60.     { BlackRook, BlackKnight, BlackBishop, BlackQueen,
  61.     BlackKing, BlackBishop, BlackKnight, BlackRook }
  62. };
  63.  
  64. static short
  65. Piece2Player(short pc)
  66. {
  67.     if (!pc)
  68.         return -1;
  69.     else if (pc <= WhiteKing)
  70.         return kWhite;
  71.     else
  72.         return kBlack;
  73. }
  74.  
  75. void
  76. InitGame(void)
  77. {
  78.     gPlaying = false;
  79.     curTime = TickCount();
  80.     LoadAllGraphics();
  81. }
  82.  
  83. void
  84. DrawGameWindow(void)
  85. {
  86. //    SetGWorld(gameWindow, maindev);
  87. //    CopyBits ((BitMap *) *(boff->portPixMap), (BitMap *) *(gameWindow->portPixMap), 
  88. //            &screenRect, &screenRect, srcCopy, nil);
  89. }
  90.  
  91. void
  92. DisposeGame(Game *game)
  93. {
  94.     if (game->isFirst)
  95.         gPrefs.gameWindPos1 = GetWindowRect((WindowPtr) game->wind);
  96.     if (game->isSecond)
  97.         gPrefs.gameWindPos2 = GetWindowRect((WindowPtr) game->wind);
  98.     DisposeWindow((WindowPtr) game->wind);
  99.     DisposPtr((Ptr) game);
  100. }
  101.  
  102.  
  103. #if TIMESTAMP
  104. void init_encrypt();
  105. void init_process_chars_from_server(void);
  106. void send_alarm(void);
  107.  
  108. #include "timeseal.h"
  109.  
  110. #endif
  111.  
  112. void
  113. StartPlaying(void)
  114. {
  115.     
  116. #if TIMESTAMP
  117.     if (gPrefs.serverType == kIcc && gPrefs.timeseal) {
  118.         init_encrypt();
  119.         init_process_chars_from_server();
  120.     }
  121.     if (gPrefs.serverType == kFics && gPrefs.timeseal) {
  122.         InitTimeseal();
  123.     }
  124.     gSentAlarm = false;
  125. #endif
  126.  
  127.     gPlaying = true;
  128.     gSetStyle = false;
  129.     gNeedPassword = true;
  130.     gCaughtPrompt = false;
  131.     gWillSetup = false;
  132.     gLookinAtStorage = false;
  133.     gCheckingVersion = 0;
  134.     strcpy(gPrompt, "fics% ");
  135.     if (gPrefs.serverType == kIcc) {
  136.         gPrompt[0] = 'a';
  137.         gCaughtPrompt = true;
  138.     }
  139. }
  140.  
  141. void
  142. StopPlaying(void)
  143. {
  144.     if (gPlaying) {
  145.         gPlaying = false;
  146.         
  147.             // clean up all games
  148.         Game *game = gGames, *nx;
  149.         while (game) {
  150.             nx = game->next;
  151.             DisposeGame(game);
  152.             game = nx;
  153.         }
  154.         gGames = nil;
  155.     }
  156. }
  157.  
  158. Game *
  159. FindGameFromWindow(WindowPtr win)
  160. {
  161.     Game *game = gGames;
  162.     while (game) {
  163.         if (game->wind == (CWindowPtr) win)
  164.             return game;
  165.         game = game->next;
  166.     }
  167.     return nil;
  168. }
  169.  
  170. void
  171. DoFlip(void)
  172. {
  173.     Game *game = FindGameFromWindow(FrontWindow());
  174.     
  175.     if (!game)
  176.         return;
  177.     
  178.     game->flip = !game->flip;
  179.     DrawGame(game);
  180. }
  181.  
  182. void
  183. DoEscapeKey(void)
  184. {
  185.     if (gClickType == kNoMove)
  186.         return;
  187.     if (gClickType == kMove || gClickType == kSetupMove)
  188.         gDragGame->board[gOrigPoint.h][gOrigPoint.v] = gOldPiece;
  189.     gDragGame->tempDest.h = -1;
  190.     DrawGameBoard(gDragGame);
  191.     gClickType = kNoMove;
  192.     ShowCursor();
  193. }
  194.  
  195. void
  196. CloseGameWindow(WindowPtr win)
  197. {
  198.     Game *game = FindGameFromWindow(win);
  199.     if (game) {
  200.             // check to see if we're dragging here
  201.         if (game == gDragGame && gClickType != kNoMove) {
  202.             gClickType = kNoMove;
  203.             ShowCursor();
  204.         }
  205.         
  206.         if (gGames == game)
  207.             gGames = game->next;
  208.         if (game->next)
  209.             game->next->prev = game->prev;
  210.         if (game->prev)
  211.             game->prev->next = game->next;
  212.             // let's tell the server if we're meant to
  213.         if (gPrefs.smartClose && game->jexiste && game->number > 0) {
  214.             if (game->relation == RELATION_OBSERVING_PLAYED)
  215.                 bprintf("unobserve %d\n", game->number);
  216.             else if (game->relation == RELATION_EXAMINING)
  217.                 bprintf("unexamine\n");
  218.         }
  219.         DisposeGame(game);
  220.     }
  221. }
  222.  
  223. void
  224. SetGameWindowSize(Game *game, short delta)
  225. {
  226.     short newh, newv;
  227.     CWindowPtr win = game->wind;
  228.     SetGWorld(win, maindev);
  229.  
  230.     newh = win->portRect.right + delta;
  231.     newv = win->portRect.bottom + delta;
  232.     SizeWindow((WindowPtr) win, newh, newv, false);
  233.     
  234.     InvalRect(&win->portRect);
  235.     
  236.     game->p2OffsetY += delta;
  237.     game->boardRect.right += delta;
  238.     game->boardRect.bottom += delta;
  239.     
  240.     game->sqsize = game->boardRect.right / 8;
  241.     
  242.     if (game->isFirst)
  243.         gPrefs.boardSize1 = game->boardRect.right;
  244.     if (game->isSecond)
  245.         gPrefs.boardSize2 = game->boardRect.right;
  246.     
  247.         // move buttons
  248.     short nnn;
  249.     for (nnn=0; nnn<kNumGameControls; nnn++)
  250.         if (game->ctl[nnn])
  251.             MoveControl(game->ctl[nnn], (**game->ctl[nnn]).contrlRect.left,
  252.                     (**game->ctl[nnn]).contrlRect.top + delta);
  253. }
  254.  
  255. void
  256. GrowGameWindow(CWindowPtr win, Point pt)
  257. {
  258.     Game *game = FindGameFromWindow((WindowPtr) win);
  259.     if (!game)
  260.         return;
  261.  
  262.     Rect sr = { kWinHeight - kSquareSize * 4, kSquareSize * 4, kWinHeight + kSquareSize * 56, kSquareSize * 64 };
  263.     if (game->footer) OffsetRect(&sr, 0, kFooterSize);
  264.     if (game->bug || game->setup) OffsetRect(&sr, kBugspace, 0);
  265.     short oldh, oldv, dh, dv, newh, newv;
  266.     
  267.     SetPort((WindowPtr) win);
  268.  
  269.         // remember current size
  270.     oldh = win->portRect.right; oldv = win->portRect.bottom;
  271.     
  272.         // do the green thumb shit
  273.     long ret = GrowWindow((WindowPtr) win, pt, &sr);
  274.     
  275.     if (!ret)        // no grow
  276.         return;
  277.     
  278.     newh = LoWord(ret); newv = HiWord(ret);
  279.     dh = newh - oldh; dv = newv - oldv;
  280.         // must keep square -- pick shortest
  281.     short delta = dh;
  282.     if (dv < dh) delta = dv;
  283.     delta -= delta % 8;        // keep aligned
  284.     
  285.     if (delta == 0)
  286.         return;
  287.     
  288.     SetGameWindowSize(game, delta);
  289. }
  290.  
  291. static Fastmap *
  292. Piece2Fastmap(short pc)
  293. {    
  294.     if (!pc)
  295.         return nil;
  296.         
  297.     short offs = gPrefs.pieceSet * 2;
  298.     
  299.     if (pc <= WhiteKing)
  300.         return bpix[Bwhite+offs][pc-1];
  301.     if (pc <= BlackKing)
  302.         return bpix[Bblack+offs][pc-WhiteKing-1];
  303.     
  304.     return nil;
  305. }
  306.  
  307. static void
  308. DrawMyGrow(Game *game)
  309. {
  310. /*    Rect r = {y - 8, x-8, y, x};
  311.     FrameRect(&r);
  312.     RGBColor col = {0xC000,0xC000,0xC000};
  313.     RGBColor ccol = {0x8000,0x8000,0x8000};
  314.     RGBForeColor(&col);
  315.     PaintRect(&r);
  316.     InsetRect(&r, 3, 3);
  317.     RGBForeColor(&ccol);
  318.     PaintRect(&r);
  319.     RGBForeColor(&rgbBlack);
  320. */
  321. //    return;
  322.     short x = game->wind->portRect.right;
  323.     short y = game->wind->portRect.bottom;
  324.     Rect gr = {0, 0, y, x};
  325.     gr.left = gr.right - 15;
  326.     gr.top = gr.bottom - 15;
  327.     ClipRect(&gr);
  328.     DrawGrowIcon((WindowPtr) game->wind);
  329.     SetRect(&gr, 0, 0, 32000, 32000);
  330.     ClipRect(&gr);
  331.  
  332. }
  333.  
  334. static void
  335. DrawBoard(Board board, Game *game)
  336. {
  337.     short x, y;
  338.     Rect r;
  339.     Fastmap *fm;
  340.     
  341.     for (x=0;x<8;x++)
  342.         for (y=0;y<8;y++) {
  343.             if (game->flip)
  344.                 r.left = (7-x) * kSquareSize;
  345.             else
  346.                 r.left = x * kSquareSize;
  347.             r.right = r.left + kSquareSize;
  348.             if (game->flip)
  349.                 r.top = y * kSquareSize;
  350.             else
  351.                 r.top = (7-y) * kSquareSize;
  352.             r.bottom = r.top + kSquareSize;
  353.             if (!((x + y) & 1))
  354.                 RGBForeColor(&gPrefs.colBlack);
  355.             else
  356.                 RGBForeColor(&gPrefs.colWhite);
  357.             PaintRect(&r);
  358.             if (x == game->tempDest.h && y == game->tempDest.v) {
  359.                     // draw an X where we're trying to go
  360.                 InsetRect(&r, 4, 4);
  361.                 RGBColor col = {0xA000, 0, 0};
  362.                 RGBForeColor(&col);
  363.                 MoveTo(r.left, r.top);
  364.                 LineTo(r.right, r.bottom);
  365.                 MoveTo(r.right, r.top);
  366.                 LineTo(r.left, r.bottom);
  367.                 InsetRect(&r, -4, -4);
  368.             }
  369.             RGBForeColor(&rgbBlack);
  370.             fm = Piece2Fastmap(board[x][y]);
  371.             if (fm)
  372.                 fm->DrawMask(boff, &r);
  373.         }
  374. }
  375.  
  376. void
  377. DrawGameBoard(Game *game)
  378. {
  379.     SetGWorld(boff, nil);
  380.     DrawBoard(game->board, game);
  381.     SetGWorld(game->wind, maindev);
  382.     Rect r = //boffrect;
  383.     //OffsetRect(&r, 0, game->bOffsetY);
  384.     game->boardRect;
  385.     CopyBits ((BitMap *) *(boff->portPixMap), (BitMap *) *(game->wind->portPixMap), 
  386.         &boffrect, &r, srcCopy, nil);
  387. }
  388.  
  389. static void
  390. DrawStatSet(Game *game, short plr)
  391. {
  392.     short len;
  393.     char buf[64];
  394.     Rect r = boffrect;
  395.     r.bottom = kStatY;
  396.     
  397.     RGBColor col = {0xC000,0xC000,0xC000};
  398.     RGBColor colW = {0xF000,0xF000,0xF000};
  399.     RGBColor colB = {0x5000,0x5000,0x5000};
  400.     RGBColor ccol = {0xB000,0x1000,0x1000};
  401.     SetGWorld(boff, nil);
  402.     TextSize(12);
  403.     TextFont(0);
  404.     RGBForeColor(&col);
  405.     PaintRect(&r);
  406.         // draw stuff if we're the current player
  407.     if (game->turn == plr && !gPrefs.minimal) {
  408.         RGBForeColor(&ccol);
  409.         r.bottom = 3;
  410.         PaintRect(&r);
  411.         r.top = kStatY - 3; r.bottom = kStatY;
  412.         PaintRect(&r);
  413.         r.top = 0;
  414.     }
  415.     RGBForeColor(&rgbBlack);
  416.  
  417.         // draw strength
  418.     len = sprintf(buf, "%d", game->strength[plr]);
  419.     MoveTo(4, 16);
  420.     DrawText(buf, 0, len);
  421.     
  422.         // draw a circle if we're the current player
  423.     if (game->turn == plr) {
  424.         RGBForeColor(&ccol);
  425.         short rad = 5;
  426.         Rect rec = {kStatY/2 - rad, 27 - rad, kStatY/2 + rad, 27 + rad};
  427.         PaintOval(&rec);
  428.         RGBForeColor(&rgbBlack);
  429.     }
  430.     
  431.             // draw time in a box
  432.         // draw time
  433.     long tm = game->ptime[plr];
  434.     len = sprintf(buf, "%c%d:%02d", tm < 0 ? '-' : ' ',
  435.                 abs(tm) / 60, abs(tm) % 60);
  436.     short plen = TextWidth(buf, 0, len);
  437.  
  438.     Rect rr = {4, 37, 20, 37 + plen + 8};
  439.     if (plr == kWhite) {
  440.         RGBForeColor(&colW);
  441.         PaintRoundRect(&rr, 10, 10);
  442.         RGBForeColor(&rgbBlack);
  443.     }
  444.     else {
  445.         RGBForeColor(&colB);
  446.         PaintRoundRect(&rr, 10, 10);
  447.         RGBForeColor(&colW);
  448.     }
  449.     MoveTo(rr.left + 4, 16);
  450.     DrawText(buf, 0, len);
  451.     RGBForeColor(&rgbBlack);
  452.     
  453.         // draw their last move
  454.     MoveTo(rr.right + 4, 16);
  455.     DrawText(game->lmove[plr], 0, strlen(game->lmove[plr]));
  456.     
  457.     TextSize(10);
  458.     TextFont(geneva);
  459.  
  460.         // draw name
  461.     Move(4, 0);
  462.     DrawText(game->name[plr], 0, strlen(game->name[plr]));
  463. }
  464.  
  465. /*
  466. static void
  467. DrawStatSet(Game *game, short plr)
  468. {
  469.     short len;
  470.     char buf[64];
  471.     Rect r = boffrect;
  472.     r.bottom = kStatY;
  473.     
  474.     RGBColor col = {0xC000,0xC000,0xC000};
  475.     RGBColor colW = {0xF000,0xF000,0xF000};
  476.     RGBColor colB = {0x5000,0x5000,0x5000};
  477.     RGBColor ccol = {0xB000,0x1000,0x1000};
  478.     SetGWorld(boff, nil);
  479.         RGBForeColor(&col);
  480.     PaintRect(&r);
  481.         // draw stuff if we're the current player
  482.     if (game->turn == plr && !gPrefs.minimal) {
  483.         RGBForeColor(&ccol);
  484.         r.bottom = 3;
  485.         PaintRect(&r);
  486.         r.top = kStatY - 3; r.bottom = kStatY;
  487.         PaintRect(&r);
  488.         r.top = 0;
  489.     }
  490.     RGBForeColor(&rgbBlack);
  491.     
  492.         // draw name
  493.     Rect rr = {4, 37, 20, 37};
  494.     if (plr == kWhite) {
  495.         rr.right += StringWidth("\pWhite: ") + 2;
  496.         RGBForeColor(&colW);
  497.         PaintRoundRect(&rr, 10, 10);
  498.         RGBForeColor(&rgbBlack);
  499.         MoveTo(rr.left + 3, 16);
  500.         DrawString("\pWhite: ");
  501.     }
  502.     else {
  503.         rr.right += StringWidth("\pBlack: ") + 2;
  504.         RGBForeColor(&colB);
  505.         PaintRoundRect(&rr, 10, 10);
  506.         RGBForeColor(&colW);
  507.         MoveTo(rr.left + 3, 16);
  508.         DrawString("\pBlack: ");
  509.         RGBForeColor(&rgbBlack);
  510.     }
  511.     Move(4, 0);
  512.     DrawText(game->name[plr], 0, strlen(game->name[plr]));
  513.  
  514.         // draw a circle if we're the current player
  515.     if (game->turn == plr) {
  516.         RGBForeColor(&ccol);
  517.         short rad = 5;
  518.         Rect rec = {kStatY/2 - rad, 27 - rad, kStatY/2 + rad, 27 + rad};
  519.         PaintOval(&rec);
  520.         RGBForeColor(&rgbBlack);
  521.     }
  522.     
  523.     len = sprintf(buf, "%d", game->strength[plr]);
  524.     MoveTo(4, 16);
  525.     DrawText(buf, 0, len);
  526.     
  527.         // draw their last move
  528.     MoveTo(192, 16);
  529.     DrawText(game->lmove[plr], 0, strlen(game->lmove[plr]));
  530.     
  531.         // draw time
  532.     long tm = game->ptime[plr];
  533.     len = sprintf(buf, "%c%d:%02d", tm < 0 ? '-' : ' ',
  534.                 abs(tm) / 60, abs(tm) % 60);
  535.     MoveTo(150, 16);
  536.     DrawText(buf, 0, len);
  537. }
  538. */
  539. void
  540. DrawGameStats(Game *game)
  541. {    
  542.     Rect r = boffrect;
  543.     r.bottom = kStatY;
  544.     Rect s;
  545.     
  546.     DrawStatSet(game, !game->flip);
  547.     MoveTo(0, kStatY-1);
  548.     Line(kBoardSize, 0);
  549.     MoveTo(0, 0);
  550.     Line(kBoardSize, 0);
  551.     s = r; OffsetRect(&s, 0, game->p1OffsetY);
  552.     SetGWorld(game->wind, maindev);
  553.     CopyBits ((BitMap *) *(boff->portPixMap), (BitMap *) *(game->wind->portPixMap), 
  554.         &r, &s, srcCopy, nil);
  555.  
  556.  
  557.     DrawStatSet(game, game->flip);
  558.     MoveTo(0, kStatY-1);
  559.     Line(kBoardSize, 0);
  560.     MoveTo(0, 0);
  561.     Line(kBoardSize, 0);
  562.     SetGWorld(game->wind, maindev);
  563.         // sometimes we have to fit grow box here -- make space for it
  564.     if (!game->bug && !game->setup && !game->footer)
  565.         if (game->boardRect.right < kBoardSize + 16) {
  566.             RGBColor colB = {0x3000,0x3000,0x3000};
  567.             RGBForeColor(&colB);
  568.             Rect s = r; OffsetRect(&s, 0, game->p2OffsetY);
  569.             s.left = kBoardSize - 16; s.right = game->wind->portRect.right;
  570.             s.right -= 15;
  571.             PaintRect(&s);
  572.             s.right += 15;
  573.             s.bottom -= 15;
  574.             PaintRect(&s);
  575.             RGBForeColor(&rgbBlack);
  576.  
  577.             r.right -= 16;
  578.         }
  579.     s = r; OffsetRect(&s, 0, game->p2OffsetY);
  580.     CopyBits ((BitMap *) *(boff->portPixMap), (BitMap *) *(game->wind->portPixMap), 
  581.         &r, &s, srcCopy, nil);
  582. }
  583.  
  584. void
  585. DrawGameHeader(Game *game)
  586. {    
  587.     Rect r = boffrect;
  588.     r.bottom = kHeader;
  589.     char buf[32];
  590.     short len;
  591.  
  592.     SetGWorld(boff, nil);
  593.     RGBColor colB = {0x3000,0x3000,0x3000};
  594.     RGBColor colW = {0xE000,0xE000,0xE000};
  595.     RGBForeColor(&colB);
  596.     PaintRect(&r);
  597.     RGBForeColor(&colW);
  598. //    MoveTo(0, plr == kWhite ? 0 : kStatY-1);
  599. //    Line(kBoardSize, 0);
  600.         
  601. //    PenMode(srcBic);
  602.     
  603.     MoveTo(8, 11);
  604. /*    DrawString("\pMove ");
  605.     short len = sprintf(buf, "%d", game->officialMove);
  606.     DrawText(buf, 0, len); */
  607.     len = sprintf(buf, "Mins: %ld  Inc: %ld", game->gameMins, game->gameInc);
  608.     DrawText(buf, 0, len);
  609.     
  610.     if (game->elapsed[0]) {
  611.         Move(8, 0);
  612.         DrawText(game->elapsed, 0, strlen(game->elapsed));
  613.     }
  614.     
  615.     Move(8, 0);
  616.     if (!game->endReason[0]) {
  617.         if ((game->relation == RELATION_OBSERVING_PLAYED) ||
  618.             (game->relation == RELATION_PLAYING_MYMOVE) ||
  619.             (game->relation == RELATION_PLAYING_NOTMYMOVE)) {
  620.             len = sprintf(buf, "-> %d:%02d <-", (short) (game->thinking / 60), (short) (game->thinking % 60));
  621.             DrawText(buf, 0, len);
  622.         }
  623.     }
  624.     else
  625.         DrawText(game->endReason, 0, strlen(game->endReason));
  626.     
  627. //    PenNormal();
  628.     RGBForeColor(&rgbBlack);
  629.  
  630.     SetGWorld(game->wind, maindev);
  631.     CopyBits ((BitMap *) *(boff->portPixMap), (BitMap *) *(game->wind->portPixMap), 
  632.         &r, &r, srcCopy, nil);
  633. }
  634.  
  635. static void
  636. DrawGameFooter(Game *game)
  637. {    
  638.     Rect r = boffrect;
  639.     r.bottom = kFooterSize;
  640.  
  641.     SetGWorld(boff, nil);
  642.     RGBColor colB = {0x3000,0x3000,0x3000};
  643.     RGBColor colW = {0xE000,0xE000,0xE000};
  644.     RGBForeColor(&colB);
  645.     PaintRect(&r);
  646. //    RGBForeColor(&colW);
  647.  
  648.     RGBForeColor(&rgbBlack);
  649.  
  650.     SetGWorld(game->wind, maindev);
  651.         // sometimes we have to fit grow box here -- make space for it
  652.     Rect dest = r;
  653.     OffsetRect(&dest, 0, game->p2OffsetY + kStatY);
  654.     if (!game->bug && game->boardRect.right < kBoardSize + 16) {
  655.         RGBColor colB = {0x3000,0x3000,0x3000};
  656.         RGBForeColor(&colB);
  657.         Rect s = dest;
  658.         s.left = kBoardSize - 16; s.right = game->wind->portRect.right;
  659.         s.right -= 15;
  660.         PaintRect(&s);
  661.         s.right += 15;
  662.         s.bottom -= 15;
  663.         PaintRect(&s);
  664.  
  665.         RGBForeColor(&rgbBlack);
  666.         r.right -= 16;
  667.     }
  668.     CopyBits ((BitMap *) *(boff->portPixMap), (BitMap *) *(game->wind->portPixMap), 
  669.         &r, &dest, srcCopy, nil);
  670.  
  671.     DrawControls((WindowPtr) game->wind);
  672. }
  673.  
  674.     // just copy the pictures in
  675. static void
  676. DrawBugSet(Game *game, short plr)
  677. {
  678.     Fastmap *fm, **find;
  679.     Rect r = {0, 0, kSquareSize * 5, kSquareSize};
  680.  
  681.     SetGWorld(boff, nil);
  682.     RGBForeColor(&bugcol);
  683.     PaintRect(&r);
  684.     RGBForeColor(&rgbBlack);
  685.     
  686.         // draw pieces
  687.     find = bpix[(plr == kWhite ? Bwhite : Bblack) + gPrefs.pieceSet * 2];
  688.     short i;
  689.     for (i=0;i<5;i++) {
  690.         Rect s = {i*kSquareSize, 0, (i+1) * kSquareSize, kSquareSize};
  691.         fm = find[i];
  692.         fm->DrawMask(boff, &s);
  693.     }
  694. }
  695.  
  696. void
  697. DrawBughouse(Game *game)
  698. {
  699.     Rect src = {0, 0, kSquareSize * 5, kSquareSize};
  700.     Rect dest = {0, game->boardRect.right + kBugspace - kBugsize,
  701.             kBugY, game->boardRect.right + kBugspace};
  702.     
  703.     DrawBugSet(game, !game->flip);
  704.     SetGWorld(game->wind, maindev);
  705.     CopyBits ((BitMap *) *(boff->portPixMap), (BitMap *) *(game->wind->portPixMap), 
  706.         &src, &dest, srcCopy, nil);
  707.  
  708.  
  709.     DrawBugSet(game, game->flip);
  710.     SetGWorld(game->wind, maindev);
  711.     OffsetRect(&dest, 0, kBugY + kBugPadding);
  712.     CopyBits ((BitMap *) *(boff->portPixMap), (BitMap *) *(game->wind->portPixMap), 
  713.         &src, &dest, srcCopy, nil);
  714.  
  715.         // extra stuff
  716.     Rect r = {kBugY, game->boardRect.right, kBugY + kBugPadding, game->boardRect.right + kBugspace};
  717.     RGBForeColor(&bugcol);
  718.     PaintRect(&r);
  719.  
  720.     r.top = kBugY * 2 + kBugPadding; r.bottom = game->wind->portRect.bottom;
  721.  
  722.     PaintRect(&r);
  723.  
  724.     RGBForeColor(&rgbBlack);
  725.     MoveTo(game->boardRect.right, 0);
  726.     Line(0, game->wind->portRect.bottom);
  727.     
  728.     DrawMyGrow(game);
  729. }
  730.  
  731. static void
  732. DrawReserveSet(Game *game, short plr)
  733. {
  734.     Rect r = {0, 0, kBugY, kBugspace - kBugsize};
  735.  
  736.     SetGWorld(boff, nil);
  737.     RGBForeColor(&bugcol);
  738.     PaintRect(&r);
  739.     RGBForeColor(&rgbBlack);
  740.     MoveTo(0, 0);
  741.     Line(0, kBugY);
  742.  
  743.     TextSize(12);
  744.     TextFont(0);
  745.     
  746.     short nnn;
  747.     for (nnn=0;nnn<5;nnn++)
  748.         if (game->reserves[plr][nnn]) {
  749.             MoveTo(4, nnn * kBugsize + kBugsize / 2 + 6);
  750.             DrawChar(game->reserves[plr][nnn] + '0');        // can't be more than 9
  751.         }
  752.     
  753.     TextSize(10);
  754.     TextFont(geneva);
  755. }
  756.  
  757. void
  758. DrawReserves(Game *game)    // text for numbers of pieces
  759. {
  760.     Rect src = {0, 0, kBugY, kBugspace - kBugsize};
  761.     Rect dest = {0, game->boardRect.right, kBugY, game->boardRect.right + kBugspace - kBugsize};
  762.     
  763.     DrawReserveSet(game, !game->flip);
  764.     SetGWorld(game->wind, maindev);
  765.     CopyBits ((BitMap *) *(boff->portPixMap), (BitMap *) *(game->wind->portPixMap), 
  766.         &src, &dest, srcCopy, nil);
  767.  
  768.     DrawReserveSet(game, game->flip);
  769.     SetGWorld(game->wind, maindev);
  770.     OffsetRect(&dest, 0, kBugY + kBugPadding);
  771.     CopyBits ((BitMap *) *(boff->portPixMap), (BitMap *) *(game->wind->portPixMap), 
  772.         &src, &dest, srcCopy, nil);
  773. }
  774.  
  775. void
  776. DrawGame(Game *game)
  777. {
  778.         // gworlds should get set automatically
  779.     DrawGameBoard(game);
  780.     DrawGameStats(game);
  781.     DrawGameHeader(game);
  782.     if (game->bug) {
  783.         DrawReserves(game);
  784.         DrawBughouse(game);
  785.     }
  786.     if (game->footer)
  787.         DrawGameFooter(game);
  788.     if (game->footer && game->bug) {
  789.             // fill in the corner
  790.     /*    Rect r = game->wind->portRect;
  791.         r.left = kBoardSize;
  792.         r.top = kWinHeight;
  793.         RGBColor colB = {0x3000,0x3000,0x3000};
  794.         RGBForeColor(&colB);
  795.         PaintRect(&r);
  796.         RGBForeColor(&rgbBlack);
  797.         */
  798.     }
  799.     if (game->boardRect.right > kBoardSize) {
  800.             // fill in some grey bits
  801.         RGBColor colB = {0x3000,0x3000,0x3000};
  802.         RGBForeColor(&colB);
  803.         Rect r;
  804.         r.right = game->boardRect.right;
  805.         r.bottom = game->bOffsetY;
  806.         r.top = 0;
  807.         r.left = kBoardSize;
  808.         PaintRect(&r);
  809.         r.bottom = game->wind->portRect.bottom;
  810.         r.top = game->boardRect.bottom;
  811.         PaintRect(&r);
  812.         RGBForeColor(&rgbBlack);
  813.     }
  814.         // draw grow icon
  815.     DrawMyGrow(game);
  816. }
  817.  
  818. void
  819. DrawGameWindow(WindowPtr win)
  820. {
  821.     Game *game = FindGameFromWindow(win);
  822.     if (game)
  823.         DrawGame(game);
  824. }
  825.  
  826. void
  827. MakeBughouse(Game *game)
  828. {
  829.     if (game->bug)
  830.         return;
  831.     
  832.     game->bug = true;
  833.     
  834.         // expand window
  835.     short sx = game->boardRect.right + kBugspace, sy = game->wind->portRect.bottom;
  836.     SizeWindow((WindowPtr) game->wind, sx, sy, false);
  837.     
  838.     DrawBughouse(game);
  839. }
  840.  
  841. void
  842. RemoveBughouse(Game *game)
  843. {
  844.     if (!game->bug)
  845.         return;
  846.     
  847.     game->bug = false;
  848.     
  849.         // shrink window
  850.     short sx = game->boardRect.right, sy = game->wind->portRect.bottom;
  851.     SizeWindow((WindowPtr) game->wind, sx, sy, false);
  852.     SetGWorld(game->wind, maindev);
  853.     DrawMyGrow(game);
  854. }
  855.  
  856. void
  857. MakeFooter(Game *game)
  858. {
  859.     if (game->footer)
  860.         return;
  861.     
  862.     game->footer = true;
  863.     
  864.         // expand window
  865.     short sx = game->wind->portRect.right, sy = game->boardRect.bottom + kStatY + kFooterSize;
  866.     SizeWindow((WindowPtr) game->wind, sx, sy, false);
  867.         // add controls
  868.     Rect bounds = {game->p2OffsetY + kStatY + 2, 24, game->p2OffsetY + kStatY + kFooterSize - 1, 56};
  869.     game->ctl[ctlStart] = NewControl((WindowPtr) game->wind, &bounds, "\p|<<",
  870.             true, 0, 0, 0, 0, ctlStart); verify(game->ctl[ctlStart]);
  871.     OffsetRect(&bounds, 38, 0);
  872.     game->ctl[ctlBack] = NewControl((WindowPtr) game->wind, &bounds, "\p<",
  873.             true, 0, 0, 0, 0, ctlBack); verify(game->ctl[ctlBack]);
  874.     OffsetRect(&bounds, 38, 0);
  875.     game->ctl[ctlForward] = NewControl((WindowPtr) game->wind, &bounds, "\p>",
  876.             true, 0, 0, 0, 0, ctlForward); verify(game->ctl[ctlForward]);
  877.     OffsetRect(&bounds, 38, 0);
  878.     game->ctl[ctlEnd] = NewControl((WindowPtr) game->wind, &bounds, "\p>>|",
  879.             true, 0, 0, 0, 0, ctlEnd); verify(game->ctl[ctlEnd]);
  880.     OffsetRect(&bounds, 44, 0); bounds.right += 20;
  881.     game->ctl[ctlRevert] = NewControl((WindowPtr) game->wind, &bounds, "\pRevert",
  882.             true, 0, 0, 0, 0, ctlRevert); verify(game->ctl[ctlRevert]);
  883.  
  884.     DrawGameFooter(game);
  885.     DrawMyGrow(game);
  886. }
  887.  
  888. Game *
  889. NewGame(char *p1, char *p2, short gameNum, Boolean flip)
  890. {
  891.     Game *game = (Game *) NewPtr(sizeof(Game));
  892.     verify(game);
  893.     
  894.         // sticky code to make windows pop up in nice places
  895.     game->isFirst = true; game->isSecond = false;
  896.     Game *gm = gGames;
  897.     while (gm) {
  898.         if (gm->isFirst)
  899.             game->isFirst = false;
  900.         gm = gm->next;
  901.     }
  902.     if (!game->isFirst) {        // well, maybe we can be second then
  903.         gm = gGames;
  904.         if (gm) {
  905.             game->isSecond = true;
  906.             while (gm) {
  907.                 if (gm->isSecond)
  908.                     game->isSecond = false;
  909.                 gm = gm->next;
  910.             }
  911.         }
  912.     }
  913.     
  914.         // make window
  915.         // now set up game window
  916.     gScratch[0] = sprintf((char *) &gScratch[1], "%d: %s vs %s", gameNum, p1, p2);
  917.     Rect gameWindowBounds = {40, 4, 40 + kWinHeight, 4 + kBoardSize};
  918.     if (game->isSecond)
  919.         OffsetRect(&gameWindowBounds, kBoardSize + 16 + kBugspace, 0);
  920.     game->wind = (CWindowPtr) NewCWindow(0L, &gameWindowBounds, gScratch, false, documentProc, (WindowPtr) -1L, true, 0);
  921.     verify(game->wind);
  922.         // remember location of window from last time
  923.     if (game->isFirst && !EmptyRect(&gPrefs.gameWindPos1))
  924.         MoveWindow((WindowPtr) game->wind, gPrefs.gameWindPos1.left, gPrefs.gameWindPos1.top, false);
  925.     else if (game->isSecond && !EmptyRect(&gPrefs.gameWindPos2))
  926.         MoveWindow((WindowPtr) game->wind, gPrefs.gameWindPos2.left, gPrefs.gameWindPos2.top, false);
  927.     ShowWindow((WindowPtr) game->wind);
  928.  
  929.     strncpy(game->name[0], p1, 127); game->name[0][127] = 0;
  930.     strncpy(game->name[1], p2, 127); game->name[1][127] = 0;
  931.     
  932.     memcpy(game->board, initialPosition, sizeof(Board));
  933.     
  934.     game->number = gameNum;
  935.     game->origNumber = gameNum;
  936.     game->jexiste = true;
  937.     game->relation = RELATION_OBSERVING_PLAYED;
  938.     game->gameMins = 0;
  939.     game->gameInc = 0;
  940.     game->elapsed[0] = 0;
  941.     
  942.         // bughouse stuff
  943.     game->bug = false;
  944.     short nnn, mmm;
  945.     for (mmm=0;mmm<2;mmm++)
  946.         for (nnn=0;nnn<5;nnn++)
  947.             game->reserves[mmm][nnn] = 0;
  948.         
  949.         // examining stuff
  950.     for (nnn=0;nnn<kNumGameControls;nnn++)
  951.         game->ctl[nnn] = 0;
  952.     game->footer = false;
  953.     game->setup = false;
  954.     
  955.     game->turn = kWhite;
  956.     
  957.     game->ptime[0] = 0;
  958.     game->ptime[1] = 0;
  959.     game->thinking = 0;
  960.     
  961.     game->strength[0] = 0; game->strength[1] = 0;
  962.     
  963.     game->flip = flip;
  964.     
  965.     game->next = gGames;
  966.     if (game->next)
  967.         game->next->prev = game;
  968.     game->prev = nil;
  969.     gGames = game;
  970.     
  971.     game->lastMove[0][0] = -1; game->lastMove[0][1] = 0;
  972.     game->lastMove[1][0] = 0; game->lastMove[1][1] = 0;
  973.     game->tempDest.h = -1;
  974.     
  975.     game->p1OffsetY = kHeader;
  976.     game->bOffsetY = kStatY + game->p1OffsetY;
  977.     game->p2OffsetY = game->bOffsetY + kBoardSize;
  978.     SetRect(&game->boardRect, 0, game->bOffsetY, kBoardSize, game->bOffsetY + kBoardSize);
  979.     game->sqsize = 32;
  980.  
  981.     game->lmove[0][0] = 0;
  982.     game->lmove[1][0] = 0;
  983.     game->officialMove = 1;
  984.     
  985.     game->endReason[0] = 0;
  986.     
  987.         // check for default sizes
  988.     if (game->isFirst && gPrefs.boardSize1 != game->boardRect.right)
  989.         SetGameWindowSize(game, gPrefs.boardSize1 - game->boardRect.right);
  990.     if (game->isSecond && gPrefs.boardSize2 != game->boardRect.right)
  991.         SetGameWindowSize(game, gPrefs.boardSize2 - game->boardRect.right);
  992.     
  993.     return game;
  994. }
  995.  
  996.     // k =  any keyboard scan code, 0-127
  997. static int isPressed(unsigned short k )
  998. {
  999.     return ( ( km[k>>3] >> (k & 7) ) & 1);
  1000. }
  1001.  
  1002. static void
  1003. ShowLastMove(void)
  1004. {
  1005.         // draw a line where the last move occurred
  1006.     WindowPtr win = FrontWindow();
  1007.     if (!win)
  1008.         return;
  1009.     Game *game = FindGameFromWindow(win);
  1010.     if (!game)
  1011.         return;
  1012.     if (game->lastMove[0][0] < 0)
  1013.         return;        // no move yet
  1014.  
  1015.     SetGWorld(game->wind, maindev);
  1016.     
  1017.     RGBColor col = {0xFFFF, 0, 0};
  1018.     RGBForeColor(&col);
  1019.     short siz = game->sqsize;
  1020.     PenSize(4, 4);
  1021.     if (game->lastMove[0][0] == game->lastMove[1][0] && game->lastMove[0][1] == game->lastMove[1][1])
  1022.         PenSize(8, 8);        // make more clear in bughouse
  1023.     if (!game->flip) {
  1024.         MoveTo(game->lastMove[0][0] * siz + (siz >> 1) - 2, (7 - game->lastMove[0][1]) * siz + (siz >> 1) - 2 + game->bOffsetY);
  1025.         LineTo(game->lastMove[1][0] * siz + (siz >> 1) - 2, (7 - game->lastMove[1][1]) * siz + (siz >> 1) - 2 + game->bOffsetY);
  1026.     }
  1027.     else {
  1028.         MoveTo(((7-game->lastMove[0][0]) * siz + (siz >> 1) - 2), (game->lastMove[0][1]) * siz + (siz >> 1) - 2 + game->bOffsetY);
  1029.         LineTo(((7-game->lastMove[1][0]) * siz + (siz >> 1) - 2), (game->lastMove[1][1]) * siz + (siz >> 1) - 2 + game->bOffsetY);
  1030.     }
  1031.     while (isPressed(optionkey)) {GetKeys((UInt32 *) km);}
  1032.     PenNormal();
  1033.     RGBForeColor(&rgbBlack);
  1034.     DrawGameBoard(game);
  1035. }
  1036.  
  1037. static void
  1038. CheckTimes(void)
  1039. {
  1040.     ulong myTime = TickCount();
  1041.     Game *game = gGames;
  1042.     while (game) {
  1043.         if (game->jexiste && game->turn >= 0
  1044.                 && game->relation != RELATION_EXAMINING
  1045.                 && game->relation != RELATION_ISOLATED_BOARD
  1046.                 && game->relation != RELATION_OBSERVING_STATIC) {
  1047.             ulong d = myTime - game->lTime;
  1048.             short ds = d / 60;
  1049.             if (ds > 0) {
  1050.                 game->lTime += ds * 60;
  1051.                 short ot = game->ptime[game->turn];
  1052.                 game->ptime[game->turn] -= ds;
  1053.                 short nt = game->ptime[game->turn];
  1054.                 if (game->relation == RELATION_PLAYING_NOTMYMOVE &&
  1055.                             gPrefs.autoFlag && ot > 0 && nt <= 0) {
  1056.                         // let's flag their asses
  1057.                     bprintf("flag\n");
  1058.                     tprintf("(Flagging opponent.)\r");
  1059.                 }
  1060. #if TIMESTAMP
  1061.                     // check time for timestamp
  1062.                 if (!gSentAlarm && gPrefs.timeseal && gPrefs.serverType == kIcc &&
  1063.                             game->relation == RELATION_PLAYING_MYMOVE &&
  1064.                             nt < 0) {
  1065.                         // let's tell server dudes
  1066.                     send_alarm();
  1067.                     gSentAlarm = true;
  1068.                 }
  1069. #endif
  1070.                 
  1071.                     // we also keep track of how long they've been thinking
  1072.                 game->thinking += ds;
  1073.                 
  1074.                 DrawGameStats(game);
  1075.                 DrawGameHeader(game);
  1076.             }
  1077.         }
  1078.         game = game->next;
  1079.         verify(game != gGames);
  1080.     }
  1081. }
  1082.  
  1083. static void DragPiece2(void);
  1084.  
  1085. void
  1086. GameIdle(void)
  1087. {
  1088.     if (!gPlaying)
  1089.         return;        // that would be bad
  1090.         
  1091.     curTime = TickCount();
  1092.     GetKeys((UInt32 *) km);
  1093.     if (isPressed(optionkey))
  1094.         ShowLastMove();
  1095.         
  1096.         // adjust time
  1097.     CheckTimes();
  1098.     DragPiece2();
  1099. }
  1100.  
  1101. static void
  1102. Point2Square(Game *game, Point *pt)
  1103. {
  1104.     pt->v -= game->bOffsetY;
  1105.  
  1106.     if (pt->v < 0) {
  1107.         pt->h = -2;
  1108.         return;
  1109.     }
  1110.     pt->h /= game->sqsize; pt->v /= game->sqsize;
  1111.     if (pt->h < 0 || pt->v < 0 || pt->h > 7 || pt->v > 7) {
  1112.         pt->h = -2;
  1113.         return;        // out of range
  1114.     }
  1115.     if (!game->flip)
  1116.         pt->v = 7 - pt->v;
  1117.     else
  1118.         pt->h = 7 - pt->h;
  1119. }
  1120.  
  1121. static void
  1122. DrawBoardSection(Game *game, Rect *r)
  1123. {
  1124.     Rect rr = *r;
  1125.     rr.right++; rr.bottom++;
  1126.     if (rr.right % kSquareSize) rr.right += kSquareSize - rr.right % kSquareSize;
  1127.     if (rr.bottom % kSquareSize) rr.bottom += kSquareSize - rr.bottom % kSquareSize;
  1128.     if (rr.right > kBoardSize) rr.right = kBoardSize;
  1129.     if (rr.bottom > kBoardSize) rr.bottom = kBoardSize;
  1130.     rr.left -= rr.left % kSquareSize;
  1131.     rr.top -= rr.top % kSquareSize;
  1132.     Rect dest = rr;
  1133.         // offset due to scaling
  1134.     dest.left = (dest.left * game->sqsize) / kSquareSize;
  1135.     dest.top = (dest.top * game->sqsize) / kSquareSize;
  1136.     dest.right = (dest.right * game->sqsize) / kSquareSize;
  1137.     dest.bottom = (dest.bottom * game->sqsize) / kSquareSize;
  1138.     OffsetRect(&dest, game->boardRect.left, game->boardRect.top);
  1139.     CopyBits((BitMap *) *(boff->portPixMap), (BitMap *) *(game->wind->portPixMap), 
  1140.         &rr, &dest, srcCopy, nil);
  1141. }
  1142.  
  1143. static Point
  1144. DragPiece(Game *game, short pc, short offx, short offy, Point origin)
  1145. {
  1146.     Fastmap *fm = Piece2Fastmap(pc);
  1147.     verify(fm);
  1148.     
  1149.     Point ms, sq;
  1150.     Boolean inSquare;
  1151.     short siz = game->sqsize;
  1152.     
  1153.     GetMouse(&ms); ms.v -= game->bOffsetY;
  1154.     HideCursor();
  1155.     Rect dirty = {0,0,0,0};
  1156.     if (origin.h >= 0) {
  1157.         if (!game->flip)
  1158.             dirty.left = origin.h * kSquareSize;
  1159.         else
  1160.             dirty.left = (7-origin.h) * kSquareSize;
  1161.         dirty.right = dirty.left + kSquareSize;
  1162.         if (!game->flip)
  1163.             dirty.top = (7 - origin.v) * kSquareSize;
  1164.         else
  1165.             dirty.top = origin.v * kSquareSize;
  1166.         dirty.bottom = dirty.top + kSquareSize;    
  1167.     }
  1168.     
  1169.     do {
  1170.         CheckTimes();
  1171.  
  1172.         SetGWorld(boff, nil);
  1173.         DrawBoard(game->board, game);
  1174.  
  1175.             // draw the piece we're dragging
  1176.         SetGWorld(game->wind, maindev);
  1177.         GetMouse(&ms);
  1178.         ms.v -= offy + game->bOffsetY; ms.h -= offx;
  1179.             // find square we're in
  1180.         inSquare = false;
  1181.         sq = ms;
  1182.         sq.h += siz / 2;
  1183.         sq.v += siz / 2;
  1184.         if ((sq.h % siz > 4) && (sq.h % siz < siz - 4)
  1185.                 && (sq.v % siz > 4) && (sq.v % siz < siz - 4)) {
  1186.             sq.v += game->bOffsetY;        // ugly, silly, but heck
  1187.             Point2Square(game, &sq);
  1188.             inSquare = sq.h >= 0;
  1189.         }
  1190.         else {
  1191.                 // some extra work to see if they dragged it completely off the board
  1192.                 // in that case, we return -2 (for setup)
  1193.             sq.v += game->bOffsetY;        // ugly, silly, but heck
  1194.             Point2Square(game, &sq);
  1195.             if (sq.h >= 0)
  1196.                 sq.h = -1;
  1197.         }
  1198.         
  1199.         SetGWorld(boff, nil);
  1200.  
  1201.             // draw target
  1202.         Rect rr = {0,0,0,0};
  1203.         if (inSquare && !EqualPt(origin, sq)) {
  1204.             if (!game->flip)
  1205.                 rr.left = sq.h * kSquareSize;
  1206.             else
  1207.                 rr.left = (7-sq.h) * kSquareSize;
  1208.             rr.right = rr.left + kSquareSize;
  1209.             if (!game->flip)
  1210.                 rr.top = (7 - sq.v) * kSquareSize;
  1211.             else
  1212.                 rr.top = sq.v * kSquareSize;
  1213.             rr.bottom = rr.top + kSquareSize;
  1214.             InsetRect(&rr, 4, 4);
  1215.             RGBColor col = {0xFFFF, 0, 0};
  1216.             RGBForeColor(&col);
  1217.             MoveTo(rr.left, rr.top);
  1218.             LineTo(rr.right, rr.bottom);
  1219.             MoveTo(rr.right, rr.top);
  1220.             LineTo(rr.left, rr.bottom);
  1221.             RGBForeColor(&rgbBlack);
  1222.             rr.right++; rr.bottom++;
  1223.             if (dirty.right > 0 && dirty.bottom > 0)
  1224.                 UnionRect(&rr, &dirty, &dirty);
  1225.             else
  1226.                 dirty = rr;        // first time through loop
  1227.         }
  1228.  
  1229.             // draw piece we're sliding around
  1230.         Rect rec = {0, 0, 32, 32};
  1231.         ms.h = (float) ms.h * 32.0 / (float) siz;
  1232.         ms.v = (float) ms.v * 32.0 / (float) siz;
  1233.         OffsetRect(&rec, ms.h, ms.v);
  1234.         fm->DrawMask(boff, &rec);
  1235.         if (dirty.right > 0 && dirty.bottom > 0)
  1236.             UnionRect(&rec, &dirty, &dirty);
  1237.         else
  1238.             dirty = rec;
  1239.         
  1240.         SetGWorld(game->wind, maindev);
  1241.         if (dirty.left < 0) dirty.left = 0;
  1242.         if (dirty.top < 0) dirty.top = 0;
  1243.         if (dirty.bottom > kBoardSize) dirty.bottom = kBoardSize;
  1244.         if (dirty.right > kBoardSize) dirty.right = kBoardSize;
  1245.         DrawBoardSection(game, &dirty);
  1246. //        Rect dest = dirty;
  1247. //        OffsetRect(&dest, game->boardRect.left, game->boardRect.top);
  1248. //        CopyBits((BitMap *) *(boff->portPixMap), (BitMap *) *(game->wind->portPixMap), 
  1249. //            &boffrect, &game->boardRect, srcCopy, nil);
  1250. //        CopyBits((BitMap *) *(boff->portPixMap), (BitMap *) *(game->wind->portPixMap), 
  1251. //            &dirty, &dest, srcCopy, nil);
  1252.             
  1253.             // prepare dirty for next loop
  1254.         dirty = rec;
  1255.         if (rr.right > 0)
  1256.             UnionRect(&rr, &dirty, &dirty);
  1257.     } while (Button());
  1258.  
  1259.     ShowCursor();
  1260.     return sq;
  1261. }
  1262.  
  1263. static char
  1264. Piece2Char(short pc)
  1265. {
  1266.         // black in capitals
  1267.     switch(pc) {
  1268.         case WhitePawn: return 'P'; case BlackPawn: return 'p';
  1269.         case WhiteKnight: return 'N'; case BlackKnight: return 'n';
  1270.         case WhiteBishop: return 'B'; case BlackBishop: return 'b';
  1271.         case WhiteRook: return 'R'; case BlackRook: return 'r';
  1272.         case WhiteQueen: return 'Q'; case BlackQueen: return 'q';
  1273.         case WhiteKing: return 'K'; case BlackKing: return 'k';
  1274.         default: return '?';
  1275.     }
  1276. }
  1277.  
  1278. static void
  1279. HandleBugClick(Game *game, Point p)
  1280. {
  1281.     short pc;
  1282.  
  1283.     short plr;
  1284.     if (p.v > kBugY + kBugPadding) {
  1285.         if (p.v > kBugY * 2 + kBugPadding)
  1286.             return;
  1287.         if (!game->flip) {
  1288.             pc = WhitePawn + (p.v - (kBugY + kBugPadding)) / kBugsize;
  1289.             plr = kWhite;
  1290.         }
  1291.         else {
  1292.             pc = BlackPawn + (p.v - (kBugY + kBugPadding)) / kBugsize;
  1293.             plr = kBlack;
  1294.         }
  1295.     }
  1296.     else if (p.v < kBugY) {
  1297.         if (!game->flip) {
  1298.             pc = BlackPawn + p.v / kBugsize;
  1299.             plr = kBlack;
  1300.         }
  1301.         else {
  1302.             pc = WhitePawn + p.v / kBugsize;
  1303.             plr = kWhite;
  1304.         }
  1305.     }
  1306.     else
  1307.         return;
  1308.     
  1309.     if (pc < WhitePawn || pc > BlackKing)
  1310.         return;
  1311.         
  1312.     if (Piece2Player(pc) != game->turn && !game->setup)
  1313.         return;        // wrong color piece
  1314.     
  1315.     Point pt = {-1, -1};
  1316.     short offs;
  1317.     if (!game->flip)
  1318.         offs = plr == kWhite ? 16 : -16;
  1319.     else
  1320.         offs = plr == kBlack ? 16 : -16;
  1321.     Point dest = DragPiece(game, pc, kBugspace + 8, 16 + offs, pt);
  1322.     
  1323.     if (dest.h < 0) {
  1324.         DrawGameBoard(game);
  1325.         return;
  1326.     }
  1327.  
  1328.     game->board[dest.h][dest.v] = pc;
  1329.     DrawGameBoard(game);
  1330.     game->tempDest = dest;
  1331.     
  1332.         // now deal with the move
  1333.     char ch = '?';
  1334.     ch = Piece2Char(pc);
  1335.     bprintf("%c@%c%c\n", ch, 'a' + dest.h, '1' + dest.v);
  1336. //    tprintf("%c@%c%c\n", ch, 'a' + dest.h, '1' + dest.v);
  1337. }
  1338.  
  1339. static void
  1340. DoFooterClick(Game *game, Point *pt)
  1341. {
  1342.     ControlHandle ch = nil;
  1343.     
  1344.         // let's see if they hit a button
  1345.     if (FindControl(*pt, (WindowPtr) game->wind, &ch))
  1346.         if (TrackControl(ch, *pt, nil)) {
  1347.             long id = GetCRefCon(ch);
  1348.             
  1349.             switch (id) {
  1350.                 case ctlBack: bprintf("backward\n"); break;
  1351.                 case ctlForward: bprintf("forward\n"); break;
  1352.                 case ctlStart: bprintf("backward 999\n"); break;
  1353.                 case ctlEnd: bprintf("forward 999\n"); break;
  1354.                 case ctlRevert: bprintf("revert\n"); break;
  1355.                 default: break;
  1356.             }
  1357.         }
  1358. }
  1359.  
  1360. static void
  1361. EndMove(void)
  1362. {
  1363.     if (gClickType != kNoMove) {
  1364.         verify(gDragGame);
  1365.         Game *game = gDragGame;
  1366.         if (gClickType == kMove) {
  1367.             if (EqualPt(gDestPoint, gOrigPoint))        // not a move
  1368.                 gDestPoint.h = -1;
  1369.             if (gDestPoint.h < 0)
  1370.                 game->board[gOrigPoint.h][gOrigPoint.v] = gOldPiece;
  1371.             else
  1372.                 game->board[gDestPoint.h][gDestPoint.v] = gOldPiece;
  1373.             if (gDestPoint.h >= 0)
  1374.                 game->tempDest = gDestPoint;
  1375.             else
  1376.                 game->tempDest.h = -1;
  1377.             DrawGameBoard(game);
  1378.             
  1379.                 // now deal with the move
  1380.             if (gDestPoint.h >= 0) {
  1381.                 bprintf("%c%c%c%c\n", 'a' + gOrigPoint.h, '1' + gOrigPoint.v, 'a' + gDestPoint.h, '1' + gDestPoint.v);
  1382.         //        tprintf("%c%c%c%c\r", 'a' + gOrigPoint.h, '1' + gOrigPoint.v, 'a' + gDestPoint.h, '1' + gDestPoint.v);
  1383.         //        tprintf("%d %d\r", gDestPoint.h, gDestPoint.v);    
  1384.             }
  1385.         }
  1386.         else if (gClickType == kSetupMove) {
  1387.             if (EqualPt(gDestPoint, gOrigPoint))        // not a move
  1388.                 gDestPoint.h = -1;
  1389.             if (gDestPoint.h < 0)
  1390.                 game->board[gOrigPoint.h][gOrigPoint.v] = gOldPiece;
  1391.             else
  1392.                 game->board[gDestPoint.h][gDestPoint.v] = gOldPiece;
  1393.             if (gDestPoint.h >= 0)
  1394.                 game->tempDest = gDestPoint;
  1395.             else
  1396.                 game->tempDest.h = -1;
  1397.             DrawGameBoard(game);
  1398.             
  1399.                 // now deal with the move
  1400.             if (gDestPoint.h >= 0) {
  1401.                     // we're in setup mode, and they're moving a piece
  1402.                     // this isn't supported in server, but why not here?  just clear and place
  1403.                 bprintf("x@%c%c\n", 'a' + gOrigPoint.h, '1' + gOrigPoint.v);        // clear old piece
  1404.                 bprintf("%c@%c%c\n", Piece2Char(gOldPiece), 'a' + gDestPoint.h, '1' + gDestPoint.v);
  1405.             }
  1406.             else if (gDestPoint.h == -2) {
  1407.                     // we're in setup mode, and they're clearing a piece off the board
  1408.                 bprintf("x@%c%c\n", 'a' + gOrigPoint.h, '1' + gOrigPoint.v);
  1409.                 game->board[gOrigPoint.h][gOrigPoint.v] = empty;
  1410.                 DrawGameBoard(game);
  1411.             }
  1412.         }
  1413.         else if (gClickType == kBugMove) {            
  1414.             if (gDestPoint.h < 0)
  1415.                 DrawGameBoard(game);
  1416.             else {
  1417.                 game->board[gDestPoint.h][gDestPoint.v] = gOldPiece;
  1418.                 DrawGameBoard(game);
  1419.                 game->tempDest = gDestPoint;
  1420.                 
  1421.                     // now deal with the move
  1422.                 char ch = '?';
  1423.                 ch = Piece2Char(gOldPiece);
  1424.                 bprintf("%c@%c%c\n", ch, 'a' + gDestPoint.h, '1' + gDestPoint.v);
  1425.             //    tprintf("%c@%c%c\n", ch, 'a' + gDestPoint.h, '1' + gDestPoint.v);
  1426.             }
  1427.         }
  1428.     }
  1429.     gClickType = kNoMove;
  1430.     ShowCursor();
  1431. }
  1432.  
  1433. static void
  1434. StartDrag(void)
  1435. {
  1436.     Point origin = gOrigPoint;
  1437.     
  1438.     HideCursor();
  1439.     SetRect(&dirty, 0, 0, 0, 0);
  1440.     gDestPoint.h = -2;
  1441.     gDestPoint.v = -2;
  1442.     if (origin.h >= 0) {
  1443.         if (!gDragGame->flip)
  1444.             dirty.left = origin.h * kSquareSize;
  1445.         else
  1446.             dirty.left = (7-origin.h) * kSquareSize;
  1447.         dirty.right = dirty.left + kSquareSize;
  1448.         if (!gDragGame->flip)
  1449.             dirty.top = (7 - origin.v) * kSquareSize;
  1450.         else
  1451.             dirty.top = origin.v * kSquareSize;
  1452.         dirty.bottom = dirty.top + kSquareSize;    
  1453.     }
  1454. }
  1455.  
  1456.     // if we're dragging when we get a server update, make sure the source remains empty
  1457. void
  1458. GotBoardFromServer(Game *game)
  1459. {
  1460.     if (gClickType == kNoMove || game != gDragGame)
  1461.         return;
  1462.     if (gOrigPoint.h < 0)
  1463.         return;        // a place
  1464.     game->board[gOrigPoint.h][gOrigPoint.v] = empty;
  1465. }
  1466.  
  1467. static void
  1468. HandleBugClick2(Game *game, Point p)
  1469. {
  1470.     short pc;
  1471.  
  1472.     short plr;
  1473.     if (p.v > kBugY + kBugPadding) {
  1474.         if (p.v > kBugY * 2 + kBugPadding)
  1475.             return;
  1476.         if (!game->flip) {
  1477.             pc = WhitePawn + (p.v - (kBugY + kBugPadding)) / kBugsize;
  1478.             plr = kWhite;
  1479.         }
  1480.         else {
  1481.             pc = BlackPawn + (p.v - (kBugY + kBugPadding)) / kBugsize;
  1482.             plr = kBlack;
  1483.         }
  1484.     }
  1485.     else if (p.v < kBugY) {
  1486.         if (!game->flip) {
  1487.             pc = BlackPawn + p.v / kBugsize;
  1488.             plr = kBlack;
  1489.         }
  1490.         else {
  1491.             pc = WhitePawn + p.v / kBugsize;
  1492.             plr = kWhite;
  1493.         }
  1494.     }
  1495.     else
  1496.         return;
  1497.     
  1498.     if (pc < WhitePawn || pc > BlackKing)
  1499.         return;
  1500.         
  1501.     if ((Piece2Player(pc) != (game->turn ^ (game->relation == RELATION_PLAYING_NOTMYMOVE))) && !game->setup)
  1502.         return;        // wrong color piece
  1503.     
  1504.     Point pt = {-1, -1};
  1505.     short offs;
  1506.     if (!game->flip)
  1507.         offs = plr == kWhite ? 16 : -16;
  1508.     else
  1509.         offs = plr == kBlack ? 16 : -16;
  1510.     gOrigPoint = pt;
  1511.     gOldPiece = pc;
  1512.     gDragGame = game;
  1513.     offx = kBugspace + 8;
  1514.     offy = 16 + offs;
  1515.     gClickType = kBugMove;
  1516.     StartDrag();
  1517.     DragPiece2();
  1518. }
  1519.  
  1520. static void
  1521. DragPiece2(void)
  1522. {
  1523.     Game *game = gDragGame;
  1524.     if (!game || gClickType == kNoMove)
  1525.         return;
  1526.  
  1527.     Fastmap *fm = Piece2Fastmap(gOldPiece);
  1528.     verify(fm);
  1529.     
  1530.     Point ms, sq;
  1531.     Boolean inSquare;
  1532.     short siz = game->sqsize;
  1533.     Point origin = gOrigPoint;
  1534.  
  1535.     ulong stTime = TickCount();
  1536.     sq = gDestPoint;
  1537.     if (Button())
  1538.     do {
  1539.         SetGWorld(boff, nil);
  1540.         DrawBoard(game->board, game);
  1541.  
  1542.             // draw the piece we're dragging
  1543.         SetGWorld(game->wind, maindev);
  1544.         GetMouse(&ms);
  1545.         ms.v -= offy + game->bOffsetY; ms.h -= offx;
  1546.             // find square we're in
  1547.         inSquare = false;
  1548.         sq = ms;
  1549.         sq.h += siz / 2;
  1550.         sq.v += siz / 2;
  1551.         if ((sq.h % siz > 4) && (sq.h % siz < siz - 4)
  1552.                 && (sq.v % siz > 4) && (sq.v % siz < siz - 4)) {
  1553.             sq.v += game->bOffsetY;        // ugly, silly, but heck
  1554.             Point2Square(game, &sq);
  1555.             inSquare = sq.h >= 0;
  1556.         }
  1557.         else {
  1558.                 // some extra work to see if they dragged it completely off the board
  1559.                 // in that case, we return -2 (for setup)
  1560.             sq.v += game->bOffsetY;        // ugly, silly, but heck
  1561.             Point2Square(game, &sq);
  1562.             if (sq.h >= 0)
  1563.                 sq.h = -1;
  1564.         }
  1565.         
  1566.         SetGWorld(boff, nil);
  1567.  
  1568.             // draw target
  1569.         Rect rr = {0,0,0,0};
  1570.         if (inSquare && !EqualPt(origin, sq)) {
  1571.             if (!game->flip)
  1572.                 rr.left = sq.h * kSquareSize;
  1573.             else
  1574.                 rr.left = (7-sq.h) * kSquareSize;
  1575.             rr.right = rr.left + kSquareSize;
  1576.             if (!game->flip)
  1577.                 rr.top = (7 - sq.v) * kSquareSize;
  1578.             else
  1579.                 rr.top = sq.v * kSquareSize;
  1580.             rr.bottom = rr.top + kSquareSize;
  1581.             InsetRect(&rr, 4, 4);
  1582.             RGBColor col = {0xFFFF, 0, 0};
  1583.             RGBForeColor(&col);
  1584.             MoveTo(rr.left, rr.top);
  1585.             LineTo(rr.right, rr.bottom);
  1586.             MoveTo(rr.right, rr.top);
  1587.             LineTo(rr.left, rr.bottom);
  1588.             RGBForeColor(&rgbBlack);
  1589.             rr.right++; rr.bottom++;
  1590.             if (dirty.right > 0 && dirty.bottom > 0)
  1591.                 UnionRect(&rr, &dirty, &dirty);
  1592.             else
  1593.                 dirty = rr;        // first time through loop
  1594.         }
  1595.  
  1596.             // draw piece we're sliding around
  1597.         Rect rec = {0, 0, 32, 32};
  1598.         ms.h = (float) ms.h * 32.0 / (float) siz;
  1599.         ms.v = (float) ms.v * 32.0 / (float) siz;
  1600.         OffsetRect(&rec, ms.h, ms.v);
  1601.         fm->DrawMask(boff, &rec);
  1602.         if (dirty.right > 0 && dirty.bottom > 0)
  1603.             UnionRect(&rec, &dirty, &dirty);
  1604.         else
  1605.             dirty = rec;
  1606.         
  1607.         SetGWorld(game->wind, maindev);
  1608.         if (dirty.left < 0) dirty.left = 0;
  1609.         if (dirty.top < 0) dirty.top = 0;
  1610.         if (dirty.bottom > kBoardSize) dirty.bottom = kBoardSize;
  1611.         if (dirty.right > kBoardSize) dirty.right = kBoardSize;
  1612.         DrawBoardSection(game, &dirty);
  1613.             
  1614.             // prepare dirty for next loop
  1615.         dirty = rec;
  1616.         if (rr.right > 0)
  1617.             UnionRect(&rr, &dirty, &dirty);
  1618.     } while (Button() && (TickCount() - stTime < 20));
  1619.  
  1620.     gDestPoint = sq;
  1621.     if (!Button()) {
  1622.         EndMove();
  1623.     }
  1624. }
  1625.  
  1626.     // pick up a piece and move it
  1627. void
  1628. HandleGameClick(Point *pt)
  1629. {
  1630.     Point p = *pt;
  1631.     
  1632.     Game *game = FindGameFromWindow(FrontWindow());
  1633.     if (!game) return;
  1634.     
  1635.         // check for growth
  1636. //    short mx = game->wind->portRect.
  1637.  
  1638.     if (gClickType != kNoMove)
  1639.         EndMove();    // shouldn't happen much, but . . .
  1640.     
  1641.     if (game->footer && pt->v >= kWinHeight)
  1642.         DoFooterClick(game, pt);
  1643.     
  1644.         // check to see if dragging pieces is valid for this board
  1645.     if (game->relation <= 0 && game->relation != RELATION_PLAYING_NOTMYMOVE)
  1646.         return;        // nope
  1647.     
  1648.     if (p.h > game->boardRect.right) {
  1649.         HandleBugClick2(game, p);
  1650.         return;
  1651.     }
  1652.     
  1653.         // find board coords
  1654.     Point2Square(game, &p);
  1655.     if (p.h < 0)
  1656.         return;        // out of range
  1657.  
  1658.     short oldPiece = game->board[p.h][p.v];
  1659.     if (oldPiece == empty)
  1660.         return;
  1661. //    if (Piece2Player(oldPiece) != game->turn && !game->setup)
  1662. //        return;        // wrong color piece
  1663.     if (game->relation == RELATION_PLAYING_MYMOVE) {
  1664.         if (game->turn == kWhite && oldPiece >= BlackPawn)
  1665.             return;        // wrong kind of piece
  1666.         if (game->turn == kBlack && oldPiece <= WhiteKing)
  1667.             return;        // wrong kind of piece
  1668.     }
  1669.     else if (game->relation == RELATION_PLAYING_NOTMYMOVE) {
  1670.         if (game->turn == kWhite && oldPiece <= WhiteKing)
  1671.             return;        // wrong kind of piece
  1672.         if (game->turn == kBlack && oldPiece >= BlackPawn)
  1673.             return;        // wrong kind of piece
  1674.     }
  1675.  
  1676.     game->board[p.h][p.v] = empty;
  1677. //    DrawGameBoard(game);
  1678.     gOrigPoint = p;
  1679.     gOldPiece = oldPiece;
  1680.     gDragGame = game;
  1681.     offx = pt->h % game->sqsize;
  1682.     offy = (pt->v - game->bOffsetY) % game->sqsize;
  1683.     gClickType = kMove;
  1684.     if (game->setup)
  1685.         gClickType = kSetupMove;
  1686.     StartDrag();
  1687.     DragPiece2();
  1688.  
  1689. /*
  1690.     if (EqualPt(dest, p))        // not a move
  1691.         dest.h = -1;
  1692.     if (dest.h < 0)
  1693.         game->board[p.h][p.v] = oldPiece;
  1694.     else
  1695.         game->board[dest.h][dest.v] = oldPiece;
  1696.     game->tempDest = dest;
  1697.     if (!(dest.h == -2 && game->setup))
  1698.         DrawGameBoard(game);
  1699.     
  1700.         // now deal with the move
  1701.     if (dest.h < 0) {
  1702.         if (dest.h == -2 && game->setup) {
  1703.                 // we're in setup mode, and they're clearing a piece off the board
  1704.             bprintf("x@%c%c\n", 'a' + p.h, '1' + p.v);
  1705.             game->board[p.h][p.v] = empty;
  1706.             DrawGameBoard(game);
  1707.         }
  1708.         return;
  1709.     }
  1710.     
  1711.     if (game->setup) {
  1712.             // we're in setup mode, and they're moving a piece
  1713.             // this isn't supported in server, but why not here?  just clear and place
  1714.         bprintf("x@%c%c\n", 'a' + p.h, '1' + p.v);        // clear old piece
  1715.         bprintf("%c@%c%c\n", Piece2Char(oldPiece), 'a' + dest.h, '1' + dest.v);
  1716.     }
  1717.     else
  1718.         bprintf("%c%c%c%c\n", 'a' + p.h, '1' + p.v, 'a' + dest.h, '1' + dest.v);
  1719. */
  1720. }